/*
 * memorywatcher.c
 *
 *  Created on: Feb 7, 2012
 *      Author: Administrator
 */
#include "utils.h"
#include <stdio.h>
#include <string.h>

#ifdef MEMORY_LEAK_WATCHER
#define watcher_struct_t struct watcher_struct
struct watcher_struct {
	char occupied;
	char file[20];
	char line[10];
	void *ptr;
	size_t size;
	struct watcher_struct *next;
};
static watcher_struct_t *memory_watcher;
static pthread_mutex_t memory_watcher_mutex;

static void show_current_memory_allocate()
{
	int memory_count;
	size_t size_count;
	memory_count = 0;
	size_count = 0;
	pthread_mutex_lock(&memory_watcher_mutex);
	watcher_struct_t *count_watcher = memory_watcher;
	while(count_watcher)
	{
		if(count_watcher->occupied)
		{
			++memory_count;
			size_count += count_watcher->size;
		}
		count_watcher = count_watcher->next;
	}
	pthread_mutex_unlock(&memory_watcher_mutex);
	LogD("allocated [%d] pointers, total size[%ld]",memory_count,(unsigned long)size_count);
}
static void show_unfreeed_memory()
{
	pthread_mutex_lock(&memory_watcher_mutex);
	watcher_struct_t *count_watcher = memory_watcher;
	while(count_watcher)
	{
		if(count_watcher->occupied)
		{
			LogD("unallocated memory:file[%s],line[%s],size[%d]",count_watcher->file,count_watcher->line,(unsigned int)count_watcher->size);
		}
		count_watcher = count_watcher->next;
	}
	pthread_mutex_unlock(&memory_watcher_mutex);
}

void *memory_watcher_calloc(char *file,int line,size_t size)
{
	pthread_mutex_lock(&memory_watcher_mutex);
	if(!memory_watcher)
		memory_watcher = calloc(sizeof(watcher_struct_t),1);
	watcher_struct_t *tmp_watcher = memory_watcher;
	while(tmp_watcher)
	{
		if(!tmp_watcher->occupied) break;
		else if(!tmp_watcher->next) tmp_watcher->next = calloc(sizeof(watcher_struct_t),1);
		tmp_watcher = tmp_watcher->next;
	}
	tmp_watcher->occupied = 1;
	pthread_mutex_unlock(&memory_watcher_mutex);
	tmp_watcher->ptr = calloc(size,1);
	tmp_watcher->size = size;
	strncpy(tmp_watcher->file,file,20);
	snprintf(tmp_watcher->line, 10,"%d",line);
	LogD("%s[%s] alloc memory,size[%d]",tmp_watcher->file,tmp_watcher->line,(unsigned int)tmp_watcher->size);

	show_current_memory_allocate();

	return tmp_watcher->ptr;
}
void *memory_watcher_realloc(char *file,int line,void *ptr, size_t size)
{
	watcher_struct_t *tmp_watcher;

	pthread_mutex_lock(&memory_watcher_mutex);
	tmp_watcher = memory_watcher;
	while(tmp_watcher)
	{
		if(tmp_watcher->ptr == ptr)
		{
			void *tmp = realloc(ptr,size);
			if(!tmp)
			{
				LogE("realloc error!!!");
				tmp_watcher = NULL;
			}
			else
			{
				tmp_watcher->ptr = tmp;
			}
			break;
		}
	}


	pthread_mutex_unlock(&memory_watcher_mutex);
	return tmp_watcher ? tmp_watcher->ptr:NULL;
}
void memory_watcher_free(char *file,int line,void *ptr)
{
	watcher_struct_t *tmp_watcher;
	pthread_mutex_lock(&memory_watcher_mutex);
	tmp_watcher = memory_watcher;
	while(tmp_watcher)
	{
		if(tmp_watcher->ptr == ptr)
		{
			LogD("%s[%d] free memory.allocated[%s][%s]",file,line,tmp_watcher->file,tmp_watcher->line);
			memset(tmp_watcher,0,sizeof(watcher_struct_t) - sizeof(watcher_struct_t *));
			break;
		}
		tmp_watcher = tmp_watcher->next;
	}
	pthread_mutex_unlock(&memory_watcher_mutex);

	show_current_memory_allocate();
	free(ptr);
}
void memory_watcher_init()
{
	memory_watcher = NULL;
	pthread_mutex_init(&memory_watcher_mutex,NULL);
}
void memory_watcher_destroy()
{
	watcher_struct_t *tmp_watcher;

	show_unfreeed_memory();

	pthread_mutex_lock(&memory_watcher_mutex);
	while(memory_watcher)
	{
		tmp_watcher = memory_watcher->next;
		free(memory_watcher);
		memory_watcher = tmp_watcher;
	}
	LogD("memory holder freeed.");
	pthread_mutex_unlock(&memory_watcher_mutex);
	pthread_mutex_destroy(&memory_watcher_mutex);
}
#endif
